package com.zzyl.serve.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.core.domain.R;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.bean.BeanUtils;
import com.zzyl.common.utils.uuid.UUID;
import com.zzyl.serve.dto.DeviceDto;
import com.zzyl.serve.vo.DeviceDetailVo;
import com.zzyl.serve.vo.DeviceReportDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.serve.mapper.DeviceMapper;
import com.zzyl.serve.domain.Device;
import com.zzyl.serve.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 设备Service业务层处理
 * 
 * @author liuyp
 * @date 2025-08-22
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient client;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     * 设备名称、设备类型、接入位置可修改
     * @param dto 设备
     * @return 结果
     */
    @Override
    public int updateDevice(DeviceDto dto)
    {
        //更新数据到华为云
        Device device = getById(dto.getId());
        if(device==null){
            throw new BaseException("该设备不存在");
        }
        if(!device.getDeviceName().equals(dto.getDeviceName())){
            UpdateDeviceRequest request = new UpdateDeviceRequest();
            request.withDeviceId(device.getIotId());
            UpdateDevice body = new UpdateDevice();
            AuthInfoWithoutSecret authInfobody = new AuthInfoWithoutSecret();
            authInfobody.withSecureAccess(true);
            body.withAuthInfo(authInfobody);
            body.withDeviceName(dto.getDeviceName());
            request.withBody(body);

            try {
                client.updateDevice(request);
            } catch (Exception e) {

                log.error("连接华为云修改设备信息失败");
                throw new BaseException("连接华为云修改设备信息失败");
            }
        }
        //更新数据库数据
        Device updateDevice = new Device();
        BeanUtils.copyProperties(dto,updateDevice);
        updateById(updateDevice);

        return 0;
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    /**
     * 从物联网中同步数据到redis中
     */
    @Override
    public void syncProductList() {
        //从物联网中查询数据
        ListProductsRequest request = new ListProductsRequest();
        ListProductsResponse response = client.listProducts(request);
        if(response.getHttpStatusCode()!=200){
            throw new BaseException("从物联网中查询产品列表失败");
        }
        //将数据存储到redis中
        redisTemplate.opsForValue().set("productList", JSONUtil.toJsonStr(response.getProducts()));

    }

    @Override
    public void register(DeviceDto dto) {
        //判断设备名称是否已经存在
        if(getOne(Wrappers.<Device>lambdaQuery().eq(Device::getDeviceName,dto.getDeviceName())) != null){
            throw new BaseException("设备名称不可重复");
        }

        //判断设备标识码是否存在
        LambdaQueryWrapper<Device> wrapper = Wrappers.<Device>lambdaQuery().eq(Device::getNodeId, dto.getNodeId());
        if(getOne(wrapper)!=null){
            throw new BaseException("设备标识码不可重复！");
        }
        //判断同一位置有没有绑定同一种产品
        LambdaQueryWrapper<Device> isLocationProductWrapper = Wrappers.<Device>lambdaQuery()
                //随身设备或固定设备
                .eq(Device::getLocationType, dto.getLocationType())
                //如果是固定设备，0楼层，1房间，2床位
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                //绑定位置
                .eq(Device::getBindingLocation, dto.getBindingLocation())
                //判断是不是同一产品
                .eq(Device::getProductKey, dto.getProductKey());
        if(getOne(isLocationProductWrapper)!=null){
            throw new BaseException("该位置/老人已经绑定了"+dto.getProductName());
        }
        //注册设备到华为云IoTDA中
        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        AddDevice body = new AddDevice();
            //设置设备标识码，必须：例如: watch001
        body.setNodeId(dto.getNodeId());
            //设置设备名称，非必须，该项目使用
        body.setDeviceName(dto.getDeviceName());
            //设置产品id，必须
        body.setProductId(dto.getProductKey());
        AuthInfo authInfo = new AuthInfo();
            //设置密钥，需存储到数据库中
        String secret = UUID.randomUUID().toString(true);
        authInfo.setSecret(secret);
        body.setAuthInfo(authInfo);
        addDeviceRequest.withBody(body);
            //发送请求到华为云
        AddDeviceResponse addDeviceResponse;
        try {
             addDeviceResponse = client.addDevice(addDeviceRequest);
        } catch (Exception e) {
            throw new BaseException("注册失败，调用华为云IotDa注册接口失败");
        }
        //将设备数据存入数据库中
        Device device = new Device();
        BeanUtils.copyProperties(dto,device);
        device.setIotId(addDeviceResponse.getDeviceId());
        device.setSecret(secret);
        save(device);

    }

    @Override
    public R<DeviceDetailVo> deviceDetail(String iotId) {
        //判断iotId是否存在
        LambdaQueryWrapper<Device> wrapper = Wrappers.<Device>lambdaQuery().eq(Device::getIotId, iotId);
        Device device = getOne(wrapper);
        if(device==null){
            return null;
        }
        //封装成DeviceDetailVo
        DeviceDetailVo vo = new DeviceDetailVo();
            //复制数据
        BeanUtils.copyProperties(device,vo);
        vo.setBindingLocation(Long.parseLong(device.getBindingLocation()));
        vo.setCreateTime(device.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
            //从华为云中获取数据,设备状态deviceStatus和激活时间activeTime
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.setDeviceId(device.getIotId());
        ShowDeviceResponse response = null;
        try {
            response = client.showDevice(showDeviceRequest);
        } catch (Exception e) {
            throw new BaseException("从iotDa中获取数据失败");
        }
        vo.setDeviceStatus(response.getStatus());
        String activeTimeStr = response.getActiveTime();
        if(StringUtils.isNotEmpty(activeTimeStr)){
            LocalDateTime dateTime = LocalDateTime.parse(activeTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
            //dateTime是0时区的时间，转换成北京东8区
            dateTime = dateTime.atZone(ZoneId.of("UTC")).withZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
            vo.setActiveTime(dateTime);
        }

        return R.ok(vo);
    }

    @Override
    public List<DeviceReportDataVo> queryServiceProperties(String iotId) {

        //从华为云中获取数据deviceService.queryServiceProperties();
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.setDeviceId(iotId);
        ShowDeviceShadowResponse response = null;
        try {
            response = client.showDeviceShadow(request);
        } catch (Exception e) {
            throw new BaseException("物联网iotDa获取设备物模型出错！");
        }
        DeviceShadowProperties reported = response.getShadow().get(0).getReported();
        Map<String, Object> properties = (Map<String, Object>) reported.getProperties();
        String eventTimeStr = reported.getEventTime();
            //转时间格式和时区
        LocalDateTime eventTime0 = LocalDateTime.parse(eventTimeStr, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
        LocalDateTime eventTime = eventTime0.atZone(ZoneId.of("UTC")).withZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
        //将数据封装返回给客户端
        List<DeviceReportDataVo> voList = new ArrayList<>();
        properties.forEach((prop,value)->{
            DeviceReportDataVo vo = new DeviceReportDataVo();
            vo.setEventTime(eventTime);
            vo.setFunctionId(prop);
            vo.setValue(value);
            voList.add(vo);
        });
        return voList;
    }

    @Override
    public void deleteDevice(String iotId) {
        //发送请求删除iotda中的设备信息
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.withDeviceId(iotId);

        try {
            DeleteDeviceResponse response = client.deleteDevice(request);
        }catch (Exception e){
            log.error("删除iotId为"+iotId+"的设备失败");
            throw new BaseException("连接华为云删除设备失败");
        }
        //删除数据库中的信息
        LambdaQueryWrapper<Device> wrapper = Wrappers.<Device>lambdaQuery().eq(Device::getIotId, iotId);
        remove(wrapper);
    }

    @Override
    public List<ServiceCapability> queryProduct(String productKey) {
        ShowProductRequest request = new ShowProductRequest();
        request.setProductId(productKey);
        ShowProductResponse response = client.showProduct(request);
        if(response.getHttpStatusCode()!=200){
            throw new BaseException("连接华为云-获取产品数据失败");
        }
        return response.getServiceCapabilities();
    }
}
